#include "TriWriter.h"
using namespace TriWriter;

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

bool TriWriter::OpenFile(const char* filename, ofstream& fout)
{
   // Try to open the file
   if(filename==NULL)
   {
      cerr << "Error: Invalid filename given to read file" << endl;
      return false;
   }
   
   /*#ifdef WIN32
     fin.open(filename, ios::in | ios::binary);
   #else*/
   fout.open(filename, ios::out);
   /*#endif*/
   
   if(!fout.rdbuf()->is_open())
   {
      cerr << "Error: file could not be opened for writing \""
         << filename << "\"" << endl;
      return false;
   }
   
   return true;
}

bool TriWriter::WriteTriFile(const char* filename, const vector<Vector3>& vs, const vector<int>& fs)
{
   ofstream ofile;
   if (!OpenFile(filename, ofile)) return false;

   bool result = WriteTriFile(ofile, vs, fs);

   ofile.close();

   return result;
}

bool TriWriter::WriteTriFile(ofstream& ofile, const vector<Vector3>& vs, const vector<int>& fs)
{
   int nv=(int)vs.size();
   int nf=(int)fs.size()/3;
   
   ofile << "TRI" << endl << endl << nv << endl << endl << nf << endl << endl;
   
   for (int i=0; i<nv; i++)
   {
       ofile << vs[i].toString().toStdString() << endl;
   }
   ofile << endl;
   for (int i=0, j=0; i<nf; i++, j+=3)
   {
      ofile << fs[j] << " " << fs[j+1] << " " << fs[j+2] << endl;
   }

   return true;
}

bool TriWriter::WriteOFFFile(const char* filename, const vector<Vector3>& vs, const vector<int>& fs)
{
   ofstream ofile;
   if (!OpenFile(filename, ofile)) return false;

   bool result = WriteOFFFile(ofile, vs, fs);

   ofile.close();

   return result;
}


bool TriWriter::WriteOFFFile(ofstream& ofile, const vector<Vector3>& vs, const vector<int>& fs)
{
   int nv=(int)vs.size();
   int nf=(int)fs.size()/3;
   
   ofile << "OFF" << endl << nv << " " << nf << " 0" << endl;
   
   for (int i=0; i<nv; i++)
   {
      ofile << vs[i].toString().toStdString() << endl;
   }
   for (int i=0, j=0; i<nf; i++, j+=3)
   {
      ofile << "3 " << fs[j] << " " << fs[j+1] << " " << fs[j+2] << endl;
   }

   return true;
}


bool TriWriter::WriteObjFile(const char* filename, const vector<Vector3>& vs, const vector<Vector3>& vn, const vector<int>& fs, const char *meshName)
{
   ofstream ofile;
   if (!OpenFile(filename, ofile)) return false;

   ofile << "#version 1" << endl;

   bool result = WriteObjFile(ofile, vs, vn, fs, meshName);

   ofile.close();

   return result;
}

bool TriWriter::WriteObjFile(ofstream& ofile, const vector<Vector3>& vs, const vector<Vector3>& vn, const vector<int>& fs, const char *meshName)
{
   int nv=(int)vs.size();
   int nn=(int)vn.size();
   int nf=(int)fs.size()/3;

   ofile << "# surface " << meshName << endl;

   for (int i=0; i<nv; i++)
   {
      ofile << "v " << vs[i].toString().toStdString() << endl;
   }
   for (int i=0; i<nn; i++)
   {
      ofile << "vn " << vn[i].toString().toStdString() << endl;
   }

   ofile << "g " << meshName << endl;

   for (int i=0, j=0; i<nf; i++, j+=3)
   {
      ofile << "f " << fs[j]+1 << "//" << fs[j]+1 << " " << fs[j+1]+1 << "//" << fs[j+1]+1 << " " << fs[j+2]+1 << "//" << fs[j+2]+1 << endl;
   }

   return true;
}


bool TriWriter::WritePOVFile(ofstream& ofile, const vector<Vector3>& vs, const vector<Vector3>& vn, const vector<int>& fs, const char *meshName, int texId, bool invertNormals)
{
   if (texId == -1) return true;

	int nv=(int)vs.size();
   int nn=(int)vn.size();
   int nf=(int)fs.size()/3;

	int i,j;
	
	// dump original surface
   ofile << "#declare " << meshName << "=" << endl;
 	ofile << "mesh2{" << endl;
	
	ofile << "  vertex_vectors{" << endl;
	ofile << "    " << nv << endl;
	for (i=0; i<nv-1; i++) {
		ofile << "    <" << -vs[i][0] << ", " << vs[i][1] << ", " << vs[i][2] << ">," << endl;	// change sign of x because coord sys of povray is right handed
		//ofile << "    <" << vs[i][0] << ", " << vs[i][1] << ", " << vs[i][2] << ">," << endl;	// change sign of x because coord sys of povray is right handed
	}
	ofile << "    <" << -vs[i][0] << ", " << vs[i][1] << ", " << vs[i][2] << ">" << endl;
	//ofile << "    <" << vs[i][0] << ", " << vs[i][1] << ", " << vs[i][2] << ">" << endl;
	ofile << "  }" << endl;

	if (nn > 0) {
		ofile << "  normal_vectors{" << endl;
		ofile << "    " << nn << endl;
		for (i=0; i<nn-1; i++) {
			//ofile << "    <" << vn[i][0] << ", " << vn[i][1] << ", " << vn[i][2] << ">," << endl;
			ofile << "    <" << -vn[i][0] << ", " << vn[i][1] << ", " << vn[i][2] << ">," << endl;
		}
		//ofile << "    <" << vn[i][0] << ", " << vn[i][1] << ", " << vn[i][2] << ">" << endl;
		ofile << "    <" << -vn[i][0] << ", " << vn[i][1] << ", " << vn[i][2] << ">" << endl;
		ofile << "  }" << endl;
	}
	ofile << "  uv_vectors{" << endl;
	ofile << "    3," << endl;
	ofile << "    <0,1>," << endl;
	ofile << "    <0,1>," << endl;
	ofile << "    <0,1>" << endl;
	ofile << "  }" << endl;

	//ofile << "  texture_list" << endl;
   //ofile << "  {" << endl;
   //ofile << "    1," << endl;
	//ofile << "    texture { mesh_tex" << texId << " }" << endl;
   //ofile << "  }" << endl;

	ofile << "  face_indices{" << endl;
	ofile << "    " << nf << endl;
	for (i=0, j=0; i<nf-1; i++, j+=3) 
		ofile << "    <" << fs[j+1] << ", " << fs[j] << ", " << fs[j+2] << ">," << endl;
		//ofile << "    <" << fs[j] << ", " << fs[j+1] << ", " << fs[j+2] << ">,0," << endl;

	//ofile << "    <" << fs[j] << ", " << fs[j+1] << ", " << fs[j+2] << ">,0" << endl;
	ofile << "    <" << fs[j+1] << ", " << fs[j] << ", " << fs[j+2] << ">" << endl;
	ofile << "  }" << endl;


	// hack to get right order of vertices for povray...
	ofile << "  uv_indices{" << endl;
	ofile << "    " << nf << endl;
	for (i=0, j=0; i<nf-1; i++, j+=3) 
		ofile << "    <0,1,2>," << endl;

	ofile << "    <0,1,2>" << endl;
	ofile << "  }" << endl;


	ofile << "    texture { mesh_tex" << texId << "_0 }" << endl;
	if (invertNormals)
		ofile << "    interior_texture { mesh_tex" << texId << "_1 }" << endl;

   ofile << "}" << endl;

	ofile << "object {" << endl;
	ofile << "  " << meshName << endl;
	ofile << "  translate <0,0,0>" << endl;
	ofile << "}" << endl << endl << endl << endl;
	

   return true;
}

